package com.ruicar.afs.cloud.finance.mq.receiver.basic.processor;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.bizcommon.voucher.service.VoucherFlowService;
import com.ruicar.afs.cloud.common.modules.contract.enums.*;
import com.ruicar.afs.cloud.common.modules.dto.mq.voucher.VoucherFlowInfoDto;
import com.ruicar.afs.cloud.common.modules.enums.BusinessType;
import com.ruicar.afs.cloud.common.mq.finance.cancel.dto.CancelDetailDto;
import com.ruicar.afs.cloud.common.mq.finance.cancel.dto.CancelSuccessDto;
import com.ruicar.afs.cloud.common.mq.rabbit.listener.AfsMqBizProcessor;
import com.ruicar.afs.cloud.common.mq.rabbit.message.MqTransCode;
import com.ruicar.afs.cloud.common.util.EmptyUtils;
import com.ruicar.afs.cloud.finance.common.entity.*;
import com.ruicar.afs.cloud.finance.common.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * <p>Description: </p>
 *
 * @author ZC.GUO
 * @version 1.0
 * @date create on 2020-07-30 19:59
 */
@AllArgsConstructor
@Slf4j
@Component
public class CancelSuccessProcessor implements AfsMqBizProcessor<CancelSuccessDto> {

    private final FinanceVirtualAccountService financeVirtualAccountService;

    private final FinanceCustUnusedFundsService financeCustUnusedFundsService;

    private final FinanceUnusedFundsHistoryService financeUnusedFundsHistoryService;

    private final FinanceTransLineService financeTransLineService;

    private final FinanceReceiptOperateService financeReceiptOperateService;

    private final FinanceOperateDetailService financeOperateDetailService;
    private final  VoucherFlowService voucherFlowService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean processMessage(CancelSuccessDto entity) throws Exception {
        return this.transData(entity);
    }

    @Override
    public MqTransCode getCode() {
        return MqTransCode.AFS_CONTRACT_BASIC_FINANCE_CONTRACT_CANCEL_AGREE;
    }

    @Override
    public boolean reQueueOnFail() {
        return false;
    }

    private boolean transData(CancelSuccessDto entity)throws Exception{
        /**  客户虚拟账户表 by ZC.GUO  **/
        FinanceVirtualAccount virtualAccount = this.handleVirtualAccount(entity);
        /**  当前待分配款项表 by ZC.GUO  **/
        this.handleCustUnusedFunds(entity,virtualAccount);
        /**  账户余额分配流水表 by ZC.GUO  **/
        this.handleUnusedFundsHistory(entity,virtualAccount);
        /**  业务操作记录表 by ZC.GUO  **/
        FinanceTransLine transLine = this.handleTransLine(entity);
        /**  来款操作记录表 by ZC.GUO  **/
        FinanceReceiptOperate receiptOperate = this.handleReceiptOperate(entity,transLine);
        /**  来款操作明细表 by ZC.GUO  **/
        this.handleOperateDetail(entity,receiptOperate,virtualAccount);

        //凭证流水信息推送
        VoucherFlowInfoDto voucherFlowInfoDto = new VoucherFlowInfoDto();
        voucherFlowInfoDto.setTransNo(String.valueOf(receiptOperate.getId()));
        voucherFlowInfoDto.setDealerName(entity.getDealerName());
        voucherFlowInfoDto.setBuriedPointNo(entity.getBuriedPointNo());
        voucherFlowInfoDto.setFinancialProducts(entity.getFinancialProducts());
        voucherFlowInfoDto.setContractNo(entity.getContractNo());
        voucherFlowInfoDto.setKeepAccountDate(new Date());
        if(BusinessTypeEnum.newCar.equals(entity.getBusinessType())){
            voucherFlowInfoDto.setBusinessType(com.ruicar.afs.cloud.common.modules.enums.BusinessType.NEW_CAR);
        } else if (BusinessTypeEnum.oldCar.equals(entity.getBusinessType())) {//新车
            voucherFlowInfoDto.setBusinessType(BusinessType.OLD_CAR);
        } else {
            log.error("业务类型:{},暂不支持！",entity.getBusinessType());
//            Assert.isTrue(false, MessageFormat.format("业务类型:{0},暂不支持！", entity.getBusinessType()));
        }
        voucherFlowService.sendFlow(voucherFlowInfoDto);
        return true;
    }


    private void handleOperateDetail(CancelSuccessDto entity,FinanceReceiptOperate receiptOperate,FinanceVirtualAccount virtualAccount){

        List<CancelDetailDto> details = entity.getDetails();
        if (EmptyUtils.isNotEmpty(details)){
            for (CancelDetailDto detailDto :details){
                FinanceOperateDetail operateDetail = new FinanceOperateDetail();
                operateDetail.setAccountId(virtualAccount.getId());
                operateDetail.setOperateId(receiptOperate.getId());
                operateDetail.setFeeType(detailDto.getFeeType());
                operateDetail.setFeeSourceTable(detailDto.getFeeSourceTable());
                operateDetail.setFeeId(detailDto.getFeeId());
                operateDetail.setReceiptDetailId(detailDto.getReceiptDetailId());
                operateDetail.setAmount(detailDto.getAmount());
                financeOperateDetailService.save(operateDetail);
            }
        }
        /**  单独处理未分配金额 by ZC.GUO  **/
        if (entity.getUnusedAmt().compareTo(BigDecimal.ZERO)>0){
            FinanceOperateDetail operateDetail = new FinanceOperateDetail();
            operateDetail.setAccountId(virtualAccount.getId());
            operateDetail.setOperateId(receiptOperate.getId());
            operateDetail.setFeeType(FeeTypeEnum.unusedFund);
            operateDetail.setFeeSourceTable(null);
            operateDetail.setFeeId(null);
            operateDetail.setReceiptDetailId(null);
            operateDetail.setAmount(entity.getUnusedAmt());
            financeOperateDetailService.save(operateDetail);
        }
    }

    private FinanceReceiptOperate handleReceiptOperate(CancelSuccessDto entity,FinanceTransLine transLine){
        FinanceReceiptOperate receiptOperate = new FinanceReceiptOperate();
        receiptOperate.setTransId(transLine.getId());
        receiptOperate.setFundsType(entity.getSourceType());
        receiptOperate.setFundsId(entity.getReceiptId());
        receiptOperate.setTime(Calendar.getInstance().getTime());
        receiptOperate.setType(ReceiptOperateTypeEnums.undo);
        receiptOperate.setAmount(entity.getCancelAmt());
        financeReceiptOperateService.save(receiptOperate);
        return receiptOperate;
    }

    private FinanceTransLine handleTransLine(CancelSuccessDto entity){
        FinanceTransLine transLine = new FinanceTransLine();
        transLine.setCustNo(entity.getCustNo());
        transLine.setOperateType(TransOpreateTypeEnums.undo);
        transLine.setOperator(entity.getOperator());
        transLine.setOperateTime(Calendar.getInstance().getTime());
        transLine.setOperateResult(ReturnCodeEnum.success);
        financeTransLineService.save(transLine);
        return transLine;
    }

    private void handleUnusedFundsHistory(CancelSuccessDto entity,FinanceVirtualAccount virtualAccount){
        /**  非对公结算类型的撤销 by ZC.GUO  **/
        if (!ReceiptSourceTypeEnum.transferAccounts.equals(entity.getSourceType())){
            FinanceUnusedFundsHistory unusedFundsHistory = new FinanceUnusedFundsHistory();
            unusedFundsHistory.setAccountId(virtualAccount.getId());
            unusedFundsHistory.setContractNo(entity.getContractNo());
            unusedFundsHistory.setFundsType(FundLineEnum.cancel);
            unusedFundsHistory.setFundId(entity.getReceiptId());
            unusedFundsHistory.setAmount(entity.getCancelAmt());
            financeUnusedFundsHistoryService.save(unusedFundsHistory);
        }
    }

    private FinanceVirtualAccount handleVirtualAccount(CancelSuccessDto entity){
        FinanceVirtualAccount virtualAccount = financeVirtualAccountService.getOne(Wrappers.<FinanceVirtualAccount>query().lambda()
                .eq(FinanceVirtualAccount::getCustNo,entity.getCustNo())
        );
        if (EmptyUtils.isNotEmpty(virtualAccount)){
            /**  对公结算类型的撤销，已入账金额直接进行冲减 by ZC.GUO  **/
            if (ReceiptSourceTypeEnum.transferAccounts.equals(entity.getSourceType())){
                virtualAccount.setTotalAmt(virtualAccount.getTotalAmt().subtract(entity.getCancelAmt()));
                virtualAccount.setUnUsedAmt(virtualAccount.getUnUsedAmt().subtract(entity.getUnusedAmt()));
            }else{
                virtualAccount.setUnUsedAmt(virtualAccount.getUnUsedAmt().subtract(entity.getUnusedAmt()).add(entity.getCancelAmt()));
            }
            virtualAccount.setUsedAmt(virtualAccount.getUsedAmt().subtract(entity.getUsedAmt()));
            virtualAccount.setCancelAmt(virtualAccount.getCancelAmt().add(entity.getCancelAmt()));
            financeVirtualAccountService.updateById(virtualAccount);
        }
        return virtualAccount;
    }


    private void handleCustUnusedFunds(CancelSuccessDto entity,FinanceVirtualAccount virtualAccount){
        FinanceCustUnusedFunds custUnusedFunds = financeCustUnusedFundsService.getOne(Wrappers.<FinanceCustUnusedFunds>query().lambda()
            .eq(FinanceCustUnusedFunds::getFundId,entity.getReceiptId())
        );
        if (EmptyUtils.isNotEmpty(custUnusedFunds)){
            /**  对公结算类型的撤销，直接删除 by ZC.GUO  **/
            if (ReceiptSourceTypeEnum.transferAccounts.equals(entity.getSourceType())){
                financeCustUnusedFundsService.removeById(custUnusedFunds.getId());
            }else{
                custUnusedFunds.setFundsType(FundsTypeEnum.storage);
                custUnusedFunds.setAmount(entity.getCancelAmt());
                custUnusedFunds.setStatus(UnusedFundsStatusEnums.locked);
                financeCustUnusedFundsService.updateById(custUnusedFunds);
            }
        }else{
            /**  非对公结算类型的撤销，无已有待分配的情况下直接新增 by ZC.GUO  **/
            if (!ReceiptSourceTypeEnum.transferAccounts.equals(entity.getSourceType())){
                custUnusedFunds = new FinanceCustUnusedFunds();
                custUnusedFunds.setAccountId(virtualAccount.getId());
                custUnusedFunds.setContractNo(entity.getContractNo());
                custUnusedFunds.setFundsType(FundsTypeEnum.storage);
                custUnusedFunds.setAmount(entity.getCancelAmt());
                custUnusedFunds.setStatus(UnusedFundsStatusEnums.locked);
                custUnusedFunds.setRevision(BigDecimal.ZERO.longValue());
                financeCustUnusedFundsService.save(custUnusedFunds);
            }
        }
    }
}
